package library.admin.service.impl;

import library.admin.domain.dto.PageDTO;
import library.admin.domain.po.BookCopies;
import library.admin.domain.po.BorrowRecord;
import library.admin.domain.query.BorrowRecordPageQuery;
import library.admin.domain.request.BorrowBookRequest;
import library.admin.domain.request.ReturnBookRequest;
import library.admin.domain.vo.BorrowRecordVO;
import library.admin.enums.BookStatus;
import library.admin.mapper.BorrowRecordsMapper;
import library.admin.service.IBorrowRecordsService;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 
 *
 */
@Slf4j
@Service
public class BorrowRecordsServiceImpl extends ServiceImpl<BorrowRecordsMapper, BorrowRecord> implements IBorrowRecordsService {
    @Override
    public PageDTO<BorrowRecordVO> queryBorrowRecordsByPage(BorrowRecordPageQuery pageQuery) {
        Long copyId = pageQuery.getCopyId();
        String title = pageQuery.getTitle();
        String name = pageQuery.getName();
        LocalDateTime minBorrowData = pageQuery.getMinBorrowData();
        LocalDateTime maxBorrowData = pageQuery.getMaxBorrowData();
        LocalDateTime minDueDate = pageQuery.getMinDueDate();
        LocalDateTime maxDueDate = pageQuery.getMaxDueDate();
        Long minBorrowDays = pageQuery.getMinBorrowDays();
        Long maxBorrowDays = pageQuery.getMaxBorrowDays();
        Page<BorrowRecordVO> page = pageQuery.toMpPageDefaultOrderBy(OrderItem.desc("borrowDays"));

        baseMapper.selectBorrowRecords(
                page, copyId, title, name, minBorrowData, maxBorrowData,
                minDueDate, maxDueDate, minBorrowDays, maxBorrowDays
        );

        return PageDTO.of(page);
    }

    @Override
    @Transactional
    public Long borrowBook(BorrowBookRequest request) {
        if (isBorrowed(request.getCopyId())) {
            throw new IllegalArgumentException("该图书复本已被借阅");
        }
        //判断该用户是否已经借了该图书的其他复本
        //查询复本对应的图书编号
        Long bookId = Db.lambdaQuery(BookCopies.class).eq(BookCopies::getId, request.getCopyId()).one().getBookId();
        //所有复本
        List<Long> copiesIds = Db.lambdaQuery(BookCopies.class).eq(BookCopies::getBookId, bookId).list().stream().map(BookCopies::getId).toList();
        log.debug("copiesIds: {}", copiesIds);
        //用户的借阅记录中是否包含该图书的复本
        BorrowRecord borrowRecord = lambdaQuery()
                .eq(BorrowRecord::getUserId, request.getUserId())
                .eq(BorrowRecord::getStatus, BookStatus.BORROWING)
                .in(BorrowRecord::getBookCopiesId, copiesIds).one();
        log.debug("borrowRecord : {}", borrowRecord);
        if (borrowRecord != null) {
            throw new IllegalArgumentException("已借阅过该图书的其他复本");
        }
        BorrowRecord saveRecord = request.toBorrowRecord();
        if (!save(saveRecord)) {
            throw new Error("save borrow record error");
        }
        log.debug("borrowBook 结束");
        return saveRecord.getId();
    }

    @Override
    public boolean isBorrowed(Long copyId) {
        BorrowRecord record = lambdaQuery()
                .eq(BorrowRecord::getBookCopiesId, copyId)
                .eq(BorrowRecord::getStatus, BookStatus.BORROWING).one();
        return record != null;
    }

    /**
     * TODO 目前没做图书整理后上架
     *
     * @param request 归还图书请求参数
     */
    @Override
    public void returnBook(ReturnBookRequest request) {
        boolean result = lambdaUpdate()
                .eq(BorrowRecord::getStatus, BookStatus.BORROWING)
                .eq(BorrowRecord::getBookCopiesId, request.getCopyId())
                .set(BorrowRecord::getStatus, BookStatus.IN_PAVILION)
                .set(BorrowRecord::getReturnDate, LocalDateTime.now())
                .update();
        if (!result) {
            throw new RuntimeException("update borrow record error");
        }
    }
}
